`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/07/25 15:06:34
// Design Name: 
// Module Name: cache_wrapper
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`include "axi_type_def.svh"

module cache_wrapper(
    input         clk,
    input         resetn, 

    //inst sram-like 
    input         inst_req     ,
    input         inst_wr      ,
    input  [1 :0] inst_size    ,
    input  [31:0] inst_addr    ,
    input  [31:0] inst_wdata   ,
    output [31:0] inst_rdata   ,
    output        inst_addr_ok ,
    output        inst_data_ok ,
    //
    input  [3:0]  inst_wstrb,
    //data sram-like 
    input         data_req     ,
    input         data_wr      ,
    input  [1 :0] data_size    ,
    input  [31:0] data_addr    ,
    input  [31:0] data_wdata   ,
    output [31:0] data_rdata   ,
    output        data_addr_ok ,
    output        data_data_ok ,
    //
    input  [3:0]  data_wstrb,
    //axi
    //ar
    output [3 :0] arid         ,
    output [31:0] araddr       ,
    output [3 :0] arlen        ,
    output [2 :0] arsize       ,
    output [1 :0] arburst      ,
    output [1 :0] arlock        ,
    output [3 :0] arcache      ,
    output [2 :0] arprot       ,
    output        arvalid      ,
    input         arready      ,
    //r           
    input  [3 :0] rid          ,
    input  [31:0] rdata        ,
    input  [1 :0] rresp        ,
    input         rlast        ,
    input         rvalid       ,
    output        rready       ,
    //aw          
    output [3 :0] awid         ,
    output [31:0] awaddr       ,
    output [3 :0] awlen        ,
    output [2 :0] awsize       ,
    output [1 :0] awburst      ,
    output [1 :0] awlock       ,
    output [3 :0] awcache      ,
    output [2 :0] awprot       ,
    output        awvalid      ,
    input         awready      ,
    //w          
    output [3 :0] wid          ,
    output [31:0] wdata        ,
    output [3 :0] wstrb        ,
    output        wlast        ,
    output        wvalid       ,
    input         wready       ,
    //b           
    input  [3 :0] bid          ,
    input  [1 :0] bresp        ,
    input         bvalid       ,
    output        bready       
);


typedef enum logic [4:0] {
   STALL_S_0      = 5'b00001,
   STALL_S_1     = 5'b00010,
   STALL_S_2     = 5'b00100,
   STALL_S_3     = 5'b01000,
   STALL_S_4     = 5'b10000,
   STALL_S_UNKNOWN = 5'bx
   } stall_state_t;
stall_state_t STALL_STATE;


axi_req_t   icache_axi_req;
axi_resp_t  icache_axi_resp;
axi_req_t   dcache_axi_req;
axi_resp_t  dcache_axi_resp;
axi_req_t   uncache_axi_req;
axi_resp_t  uncache_axi_resp;
bit i_stall;
bit d_stall;
//inst_req_control
bit inst_req_t;
bit data_req_t;





assign inst_req_t = data_req ? 1'b0 : inst_req;
//map uncache
wire kseg1 = data_addr[31:30] == 2'b10;
wire kseg0 = data_addr[31:29] == 3'b100;
bit u_cache; 
bit uncache_data_ok;

assign u_cache=kseg1&&!kseg0;
//assign u_cache=1;
bit [31:0] data_addr_mapped ;

assign data_addr_mapped =  {3'b0,data_addr[28:0]} ;
//assign data_addr_mapped = data_addr - 32'hA0000000;

bit d_data_ok;
bit u_data_ok;
assign data_data_ok = d_data_ok || u_data_ok;

bit u_addr_ok;

bit [31:0]d_data_rdata;
bit [31:0]u_data_rdata;
assign data_rdata  = u_cache ? u_data_rdata : d_data_rdata;


cache_onebram #(.CONST_W_CACHE(4'd0), .CONST_R_CACHE(4'd0)) icache(
    .clk           (clk),
    .resetn        (resetn),
    .data_ok       (inst_data_ok),
    
    .addren        (inst_req_t),//ren 
    .PHY_ADDR      (inst_addr),
    .RD_wr         (inst_wr),
    .DATAin        (inst_wdata),
    .DATAout       (inst_rdata),// inst_sram_rdata, data_sram_rdata
    .axi_req       (icache_axi_req),
    .axi_resp      (icache_axi_resp),
    .wstrb         (4'b0)
  ); 
  

  
  cache_onebram #(.CONST_W_CACHE(4'd1), .CONST_R_CACHE(4'd1)) dcache(
    .clk           (clk),
    .resetn        (resetn),

    .addren        (data_req && !u_cache),//ren 
    .data_ok       (d_data_ok),
    .stall         (d_stall),//inst_cache_stall, data_cache_stall
    .PHY_ADDR      (data_addr_mapped),
    .RD_wr         (data_wr),
    .DATAin        (data_wdata),
    .DATAout       (d_data_rdata),// inst_sram_rdata, data_sram_rdata
    .wstrb         (data_wstrb),

    .axi_req       (dcache_axi_req),
    .axi_resp      (dcache_axi_resp)

  );
  
uncache_2 #(.CONST_W_CACHE(4'd2), .CONST_R_CACHE(4'd2)) uncache(
    .clk          (clk),
    .resetn       (resetn), 

    .data_req     (data_req && u_cache),
    .data_wr      (data_wr),
    .data_size    (data_size),
    .data_addr    (data_addr_mapped),
    .data_wdata   (data_wdata),
    .data_rdata   (u_data_rdata),
    .data_addr_ok (u_addr_ok),
    .data_data_ok (u_data_ok),

    .axi_req      (uncache_axi_req),
    .axi_resp     (uncache_axi_resp),

    .inst_req     (1'b0)
);


axi_crossbar_3x1 crossbar (
  .aclk(clk),                    // input wire aclk
  .aresetn(resetn),              // input wire aresetn
  
  .s_axi_awid         ({icache_axi_req.AWID    , dcache_axi_req.AWID     , uncache_axi_req.AWID    }),        // input wire [7 : 0] s_axi_awid
  .s_axi_awaddr       ({icache_axi_req.AWADDR  , dcache_axi_req.AWADDR   , uncache_axi_req.AWADDR  }),    // input wire [63 : 0] s_axi_awaddr
  .s_axi_awlen        ({icache_axi_req.AWLEN   , dcache_axi_req.AWLEN    , uncache_axi_req.AWLEN   }),      // input wire [7 : 0] s_axi_awlen
  .s_axi_awsize       ({icache_axi_req.AWSIZE  , dcache_axi_req.AWSIZE   , uncache_axi_req.AWSIZE  }),    // input wire [5 : 0] s_axi_awsize
  .s_axi_awburst      ({icache_axi_req.AWBURST , dcache_axi_req.AWBURST  , uncache_axi_req.AWBURST }),  // input wire [3 : 0] s_axi_awburst
  .s_axi_awlock       ({icache_axi_req.AWLOCK  , dcache_axi_req.AWLOCK   , uncache_axi_req.AWLOCK  }),    // input wire [3 : 0] s_axi_awlock
  .s_axi_awcache      ({icache_axi_req.AWCACHE , dcache_axi_req.AWCACHE  , uncache_axi_req.AWCACHE }),  // input wire [7 : 0] s_axi_awcache
  .s_axi_awprot       ({icache_axi_req.AWPROT  , dcache_axi_req.AWPROT   , uncache_axi_req.AWPROT  }),    // input wire [5 : 0] s_axi_awprot
  .s_axi_awqos        ({icache_axi_req.AWQOS   , dcache_axi_req.AWQOS    , uncache_axi_req.AWQOS   }),      // input wire [7 : 0] s_axi_awqos
  .s_axi_awvalid      ({icache_axi_req.AWVALID , dcache_axi_req.AWVALID  , uncache_axi_req.AWVALID }),  // input wire [1 : 0] s_axi_awvalid
  .s_axi_awready      ({icache_axi_resp.AWREADY, dcache_axi_resp.AWREADY , uncache_axi_resp.AWREADY }),  // output wire [1 : 0] s_axi_awready

  .s_axi_wid          ({icache_axi_req.WID     , dcache_axi_req.WID      , uncache_axi_req.WID     }),          // input wire [7 : 0] s_axi_wid
  .s_axi_wdata        ({icache_axi_req.WDATA   , dcache_axi_req.WDATA    , uncache_axi_req.WDATA   }),      // input wire [63 : 0] s_axi_wdata
  .s_axi_wstrb        ({icache_axi_req.WSTRB   , dcache_axi_req.WSTRB    , uncache_axi_req.WSTRB   }),      // input wire [7 : 0] s_axi_wstrb
  .s_axi_wlast        ({icache_axi_req.WLAST   , dcache_axi_req.WLAST    , uncache_axi_req.WLAST   }),      // input wire [1 : 0] s_axi_wlast
  .s_axi_wvalid       ({icache_axi_req.WVALID  , dcache_axi_req.WVALID   , uncache_axi_req.WVALID  }),    // input wire [1 : 0] s_axi_wvalid
  .s_axi_wready       ({icache_axi_resp.WREADY , dcache_axi_resp.WREADY  , uncache_axi_resp.WREADY  }),    // output wire [1 : 0] s_axi_wready

  .s_axi_bid          ({icache_axi_resp.BID    , dcache_axi_resp.BID     , uncache_axi_resp.BID     }),          // output wire [7 : 0] s_axi_bid
  .s_axi_bresp        ({icache_axi_resp.BRESP  , dcache_axi_resp.BRESP   , uncache_axi_resp.BRESP   }),      // output wire [3 : 0] s_axi_bresp
  .s_axi_bvalid       ({icache_axi_resp.BVALID , dcache_axi_resp.BVALID  , uncache_axi_resp.BVALID  }),    // output wire [1 : 0] s_axi_bvalid
  .s_axi_bready       ({icache_axi_req.BREADY  , dcache_axi_req.BREADY   , uncache_axi_req.BREADY  }),    // input wire [1 : 0] s_axi_bready

  .s_axi_arid         ({icache_axi_req.ARID    , dcache_axi_req.ARID     , uncache_axi_req.ARID    }),        // input wire [7 : 0] s_axi_arid
  .s_axi_araddr       ({icache_axi_req.ARADDR  , dcache_axi_req.ARADDR   , uncache_axi_req.ARADDR  }),    // input wire [63 : 0] s_axi_araddr
  .s_axi_arlen        ({icache_axi_req.ARLEN   , dcache_axi_req.ARLEN    , uncache_axi_req.ARLEN   }),      // input wire [7 : 0] s_axi_arlen
  .s_axi_arsize       ({icache_axi_req.ARSIZE  , dcache_axi_req.ARSIZE   , uncache_axi_req.ARSIZE  }),    // input wire [5 : 0] s_axi_arsize
  .s_axi_arburst      ({icache_axi_req.ARBURST , dcache_axi_req.ARBURST  , uncache_axi_req.ARBURST }),  // input wire [3 : 0] s_axi_arburst
  .s_axi_arlock       ({icache_axi_req.ARLOCK  , dcache_axi_req.ARLOCK   , uncache_axi_req.ARLOCK  }),    // input wire [3 : 0] s_axi_arlock
  .s_axi_arcache      ({icache_axi_req.ARCACHE , dcache_axi_req.ARCACHE  , uncache_axi_req.ARCACHE }),    // input wire [7 : 0] s_axi_arcache
  .s_axi_arprot       ({icache_axi_req.ARPROT  , dcache_axi_req.ARPROT   , uncache_axi_req.ARPROT  }),      // input wire [5 : 0] s_axi_arprot
  .s_axi_arqos        ({icache_axi_req.ARQOS   , dcache_axi_req.ARQOS    , uncache_axi_req.ARQOS    }),        // input wire [7 : 0] s_axi_arqos
  .s_axi_arvalid      ({icache_axi_req.ARVALID , dcache_axi_req.ARVALID  , uncache_axi_req.ARVALID }),    // input wire [1 : 0] s_axi_arvalid
  .s_axi_arready      ({icache_axi_resp.ARREADY, dcache_axi_resp.ARREADY , uncache_axi_resp.ARREADY }),    // output wire [1 : 0] s_axi_arready

  .s_axi_rid          ({icache_axi_resp.RID    , dcache_axi_resp.RID     , uncache_axi_resp.RID     }),            // output wire [1 : 0] s_axi_rid
  .s_axi_rdata        ({icache_axi_resp.RDATA  , dcache_axi_resp.RDATA   , uncache_axi_resp.RDATA   }),        // output wire [63 : 0] s_axi_rdata
  .s_axi_rresp        ({icache_axi_resp.RRESP  , dcache_axi_resp.RRESP   , uncache_axi_resp.RRESP   }),        // output wire [3 : 0] s_axi_rresp
  .s_axi_rlast        ({icache_axi_resp.RLAST  , dcache_axi_resp.RLAST   , uncache_axi_resp.RLAST   }),        // output wire [1 : 0] s_axi_rlast
  .s_axi_rvalid       ({icache_axi_resp.RVALID , dcache_axi_resp.RVALID  , uncache_axi_resp.RVALID  }),      // output wire [1 : 0] s_axi_rvalid
  .s_axi_rready       ({icache_axi_req.RREADY  , dcache_axi_req.RREADY   , uncache_axi_req.RREADY  }),      // input wire [1 : 0] s_axi_rready

  .m_axi_awid        ( awid),        // output wire [3 : 0] m_axi_awid
  .m_axi_awaddr      ( awaddr),    // output wire [31 : 0] m_axi_awaddr
  .m_axi_awlen       ( awlen),      // output wire [3 : 0] m_axi_awlen
  .m_axi_awsize      ( awsize),    // output wire [2 : 0] m_axi_awsize
  .m_axi_awburst     ( awburst),  // output wire [1 : 0] m_axi_awburst
  .m_axi_awlock      ( awlock),    // output wire [1 : 0] m_axi_awlock
  .m_axi_awcache     ( awcache),  // output wire [3 : 0] m_axi_awcache
  .m_axi_awprot      ( awprot),    // output wire [2 : 0] m_axi_awprot
  .m_axi_awqos       ( ),      // output wire [3 : 0] m_axi_awqos
  .m_axi_awvalid     ( awvalid),  // output wire [0 : 0] m_axi_awvalid
  .m_axi_awready     ( awready),  // input wire [0 : 0] m_axi_awready

  .m_axi_wid         ( wid),          // output wire [3 : 0] m_axi_wid
  .m_axi_wdata       ( wdata),      // output wire [31 : 0] m_axi_wdata
  .m_axi_wstrb       ( wstrb),      // output wire [3 : 0] m_axi_wstrb
  .m_axi_wlast       ( wlast),      // output wire [0 : 0] m_axi_wlast
  .m_axi_wvalid      ( wvalid),    // output wire [0 : 0] m_axi_wvalid
  .m_axi_wready      ( wready),    // input wire [0 : 0] m_axi_wready

  .m_axi_bid         ( bid),          // input wire [3 : 0] m_axi_bid
  .m_axi_bresp       ( bresp),      // input wire [1 : 0] m_axi_bresp
  .m_axi_bvalid      ( bvalid),    // input wire [0 : 0] m_axi_bvalid
  .m_axi_bready      ( bready),    // output wire [0 : 0] m_axi_bready

  .m_axi_arid        ( arid),        // output wire [3 : 0] m_axi_arid
  .m_axi_araddr      ( araddr),    // output wire [31 : 0] m_axi_araddr
  .m_axi_arlen       ( arlen),      // output wire [3 : 0] m_axi_arlen
  .m_axi_arsize      ( arsize),    // output wire [2 : 0] m_axi_arsize
  .m_axi_arburst     ( arburst),  // output wire [1 : 0] m_axi_arburst
  .m_axi_arlock      ( arlock),    // output wire [1 : 0] m_axi_arlock
  .m_axi_arcache     ( arcache),  // output wire [3 : 0] m_axi_arcache
  .m_axi_arprot      ( arprot),    // output wire [2 : 0] m_axi_arprot
  .m_axi_arqos       ( ),      // output wire [3 : 0] m_axi_arqos
  .m_axi_arvalid     ( arvalid),  // output wire [0 : 0] m_axi_arvalid
  .m_axi_arready     ( arready),  // input wire [0 : 0] m_axi_arready

  .m_axi_rid         ( rid),          // input wire [3 : 0] m_axi_rid
  .m_axi_rdata       ( rdata),      // input wire [31 : 0] m_axi_rdata
  .m_axi_rresp       ( rresp),      // input wire [1 : 0] m_axi_rresp
  .m_axi_rlast       ( rlast),      // input wire [0 : 0] m_axi_rlast
  .m_axi_rvalid      ( rvalid),    // input wire [0 : 0] m_axi_rvalid
  .m_axi_rready      ( rready)    // output wire [0 : 0] m_axi_rready
);


endmodule
